export class HTMLActuator {
  tileContainer: any;
  scoreContainer: any;
  bestContainer: any;
  messageContainer: any;
  score: number;
  limit: number = 11//最大幂数

  constructor(tileContainer: any, scoreContainer: any, bestContainer: any, messageContainer: any) {
    this.tileContainer = tileContainer;
    this.scoreContainer = scoreContainer;
    this.bestContainer = bestContainer;
    this.messageContainer = messageContainer;

    this.score = 0;
  }
  // 更新页面网格样式和内容
  actuate(grid: { cells: any[]; }, metadata: { score: any; bestScore: any; terminated: any; over: any; won: any; }) {
    const self = this;
    console.log(grid, metadata);

    window.requestAnimationFrame(() => {
      self.clearContainer(self.tileContainer);

      grid.cells.forEach(column => {
        column.forEach((cell: any) => {
          if (cell) {
            self.addTile(cell);
          }
        });
      });

      self.updateScore(metadata.score);
      self.updateBestScore(metadata.bestScore);

      if (metadata.terminated) {
        if (metadata.over) {
          self.message(false); // You lose
        } else if (metadata.won) {
          self.message(true); // You win!
        }
      }
    });
  }

  // Continues the game (both restart and keep playing)
  continueGame() {
    this.clearMessage();
  }

  clearContainer(container: { firstChild: any; removeChild: (arg0: any) => void; }) {
    while (container.firstChild) {
      container.removeChild(container.firstChild);
    }
  }

  addTile(tile: { previousPosition: { x: any; y: any; }; x: any; y: any; value: any | number | null; mergedFrom: any[]; }) {
    const self = this;

    const wrapper = document.createElement("div");
    const inner = document.createElement("div");
    const position = tile.previousPosition || { x: tile.x, y: tile.y };
    const positionClass = this.positionClass(position);

    // We can't use classlist because it somehow glitches when replacing classes
    const classes = ["tile", "tile-" + tile.value, positionClass];

    if (tile.value > Math.pow(2, this.limit)) classes.push("tile-super");

    this.applyClasses(wrapper, classes);

    inner.classList.add("tile-inner");
    inner.textContent = tile.value;

    // 三种砖块状态样式:1.移动砖块 2.合并砖块 3.新砖块
    if (tile.previousPosition) {
      // tile之前发生移动,需要先移动到previousPosition,再移动到当前位置
      window.requestAnimationFrame(() => {
        // 确保在下一帧中更新瓦片的位置
        classes[2] = self.positionClass({ x: tile.x, y: tile.y });
        self.applyClasses(wrapper, classes); // Update the position
      });
    } else if (tile.mergedFrom) {
      classes.push("tile-merged");
      this.applyClasses(wrapper, classes);

      // Render the tiles that merged
      tile.mergedFrom.forEach(merged => {
        self.addTile(merged);
      });
    } else {
      classes.push("tile-new");
      this.applyClasses(wrapper, classes);
    }

    // Add the inner part of the tile to the wrapper
    wrapper.appendChild(inner);

    // Put the tile on the board
    this.tileContainer.appendChild(wrapper);
  }

  applyClasses(element: HTMLDivElement, classes: any[]) {
    element.setAttribute("class", classes.join(" "));
  }

  normalizePosition(position: { x: number; y: number; }) {
    return { x: position.x + 1, y: position.y + 1 };
  }

  positionClass(position: { x: any; y: any; }) {
    position = this.normalizePosition(position);
    return "tile-position-" + position.x + "-" + position.y;
  }

  updateScore(score: number) {
    this.clearContainer(this.scoreContainer);

    const difference = score - this.score;
    this.score = score;

    this.scoreContainer.textContent = this.score;

    if (difference > 0) {
      const addition = document.createElement("div");
      addition.classList.add("score-addition");
      addition.textContent = "+" + difference;

      this.scoreContainer.appendChild(addition);
    }
  }

  updateBestScore(bestScore: any) {
    this.bestContainer.textContent = bestScore;
  }

  message(won: boolean) {
    const type = won ? "game-won" : "game-over";
    const message = won ? "You win!" : "Game over!";

    this.messageContainer.classList.add(type);
    this.messageContainer.getElementsByTagName("p")[0].textContent = message;
  }

  clearMessage() {
    // IE only takes one value to remove at a time.
    this.messageContainer.classList.remove("game-won");
    this.messageContainer.classList.remove("game-over");
  }
}